# -*- coding: utf-8 -*-
import ast
import base64
import json
from collections import OrderedDict

import requests
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
from Crypto.Hash import SHA
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5 as Signature_pkcs1_v1_5
from django.conf import settings

from async import async_job
from common.cache import redis_cache
from common.channel.pay import check_channel_order
from common.order import db as order_db
from common.order.model import PAY_STATUS
from common.utils import track_logging
from common.utils.exceptions import ParamError

_LOGGER = track_logging.getLogger(__name__)

# 超级星
APP_CONF = {
    '201706020211343': {
        # witch 支付宝扫码 2.5%（50-5000）D0结算
        # 支付宝wap 100-10000
        'gateway': 'https://www.superstarpay.com/gateway/orderPaySweepCode',
        'h5_gateway': 'https://www.superstarpay.com/gateway/orderPay',
        'union_quick_gateway': 'https://www.superstarpay.com/gateway/orderPay',
        'query_gateway': 'https://www.superstarpay.com/gateway/queryPaymentRecord',
        'terminal_no': '201706021327537',
        'pub_key': """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDWer/PdAnCxNLVXc0NYHOXT+I
fX2tfjHl1er4N1NYHE6sL4eaEmsBlL1Ve0CRrDku5rUW6hqXhFYq5lXg+HuE33EB
DMC0AMvlAhoe8+bXeTcwHqMun7EgvHqYHZZkBZzt8/GNfeX7FSSjxDA7EXbGG88C
NM3gLnWCjghUicRc7QIDAQAB
-----END PUBLIC KEY-----""",
        'pri_key': """-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQDDWer/PdAnCxNLVXc0NYHOXT+IfX2tfjHl1er4N1NYHE6sL4ea
EmsBlL1Ve0CRrDku5rUW6hqXhFYq5lXg+HuE33EBDMC0AMvlAhoe8+bXeTcwHqMu
n7EgvHqYHZZkBZzt8/GNfeX7FSSjxDA7EXbGG88CNM3gLnWCjghUicRc7QIDAQAB
AoGAddPBayx0ZWhHvfORz7rKTZdu37uZV1C7df5+GDL+oTGJvk94wdSEGFMHlAyg
WH0BjKl45pZTbbpTYtLFT8lwbhlYJAH3x5iHBPs/lAVzgXKk71RS7ibaPNSCPZ3+
pNtdyhPNmqPSurQuj1SuralZELONZ6xkqoxlpnODA59X3MECQQDrnobhP0PH7KtR
JcBfA6Odccn9oTq1iZ9NXGc8imz+OqaedyhC10n2o93zNudmNA3c9nHhm/mTRgKj
rltIu3JdAkEA1D+1wd3ESDDZS//Awu/QAAXP3Xi2GaYPainDYILA4XsMJmd9BY38
XGNwPMply72m1vxKtN4eKmTM3YMzXPoL0QJAT6i39z1ZYCU+wl+eC0GCtn87CDnT
TH7r0c7UxF4UfVs868RjYz3ALte1+T1tvFsK+NKFK/58wXLg/4+6IvvkrQJASeYM
wH0YNBJd9eoMEVMx1nAvmWrH7FI3F72GuvmLcnZHGq/5hY+UCA7PKztFChT0G/In
iKW1VwlVkuJ1Za/hoQJARdbextBTjpD3fzoYt26wHHZZ+dSsFhCcnCVORp9mIlGU
HHFgUr43UfbS6TGHAn2t7iSe3bWDWsd1qb48yNVXOw==        
-----END RSA PRIVATE KEY-----""",
        'star_pub': '''-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCabJDz/66tGW6J0SBHI3zTqz+v
B7lkBwEcSnnaNJ6mAZ64Garc4Ax9lcFV9aUI3/v/w7LRnhPRnMCHc9HeBFS66jPi
xlvk3cB/TYsVoxuQInTE/VmQDv+9cRlKYpemULGr6VoeOzAoEHz68g/YUZCjFBxb
hTyOKutBoCorsAmQeQIDAQAB
-----END PUBLIC KEY-----''',
    },
    '201812212110060': {
        # DWC 支付宝扫码 2.5%（50-5000）D0结算
        # 支付宝wap 100-10000
        'gateway': 'https://www.superstarpay.com/gateway/orderPaySweepCode',
        'h5_gateway': 'https://www.superstarpay.com/gateway/orderPay',
        'union_quick_gateway': 'https://www.superstarpay.com/gateway/orderPay',
        'query_gateway': 'https://www.superstarpay.com/gateway/queryPaymentRecord',
        'terminal_no': '201812211006429',
        'pub_key': """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC82mGKtZRL4yYa8SJ03Gx7B/ki
U2RRxERa/FuN4KpOt3a0mH4vxRFMvB6blVaJjbCyIhZPwV7hmKHfEnFaWFBJuMv2
Aub0fNgtjmFxf1vnRGF1QmCgirEVePACnXNw8Y4oYXfuNa5aE86cAPVP4oXw2ldS
aJc0txwbdvew4ptcdwIDAQAB
-----END PUBLIC KEY-----""",
        'pri_key': """-----BEGIN RSA PRIVATE KEY-----
MIICXwIBAAKBgQC82mGKtZRL4yYa8SJ03Gx7B/kiU2RRxERa/FuN4KpOt3a0mH4v
xRFMvB6blVaJjbCyIhZPwV7hmKHfEnFaWFBJuMv2Aub0fNgtjmFxf1vnRGF1QmCg
irEVePACnXNw8Y4oYXfuNa5aE86cAPVP4oXw2ldSaJc0txwbdvew4ptcdwIDAQAB
AoGBAICGtz+pmEWVT8eiOGsD4KhSotEjo/Cp/ENX4A9MyVtNLPJ3ndlw6vcoSERm
fECdN5Xj8P9SgPpT4EZqzM5JsElv8td6JiZJHu2f2XxA9Up+Afu4GUwk2OeKagGI
Linn/1zD1bfqqHIiivjPfmSjXUc5TcDtnWwlhHnFmMdet8fRAkEA7GR+oPI1DJHy
e74cMsrUDVDQ3nM4UhQ5fBbhws34i+uv0w1rXxztb9ez0VEJb1YMcKuPVta+JDq7
n45qDqmrWwJBAMyEcYLSzQ6luQrQcj9Se0duiHARD3lK6AWcBjiVUYQDWhVXTsEf
ZVhvjuW7JCazcROsgb6GWzaSWtvocFn4ShUCQQC6baLkAUBPEobeihapBAbqHXMs
DEg9iw+uykjvngrHJm+6jZnBIAotKzr39+Xt9TnIXbSksqSv49X2RpVjzPGDAkEA
rNfGAvVa/eULJNuTonZ335/HyUZx2GV4/7yj+VAgizw19tFJqqd5BCuMDhWB8P84
MpNZN4bfMZixFyczRKY1HQJBALPe+YcIZAOqkok4OTRBd3xPbTkFDSck+TmyYVwM
A78iAL91jgtY8gOecPtHL0UEyf5fNLNmS0Hy7zIgktdIwkc=
-----END RSA PRIVATE KEY-----""",
        'star_pub': '''-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCabJDz/66tGW6J0SBHI3zTqz+v
B7lkBwEcSnnaNJ6mAZ64Garc4Ax9lcFV9aUI3/v/w7LRnhPRnMCHc9HeBFS66jPi
xlvk3cB/TYsVoxuQInTE/VmQDv+9cRlKYpemULGr6VoeOzAoEHz68g/YUZCjFBxb
hTyOKutBoCorsAmQeQIDAQAB
-----END PUBLIC KEY-----''',
    },
    '201802060615123': {
        # 泰坦 支付宝扫码 2.5%（50-5000）D0结算
        # 支付宝wap 100-10000
        'gateway': 'https://www.superstarpay.com/gateway/orderPaySweepCode',
        'h5_gateway': 'https://www.superstarpay.com/gateway/orderPay',
        'union_quick_gateway': 'https://www.superstarpay.com/gateway/orderPay',
        'query_gateway': 'https://www.superstarpay.com/gateway/queryPaymentRecord',
        'terminal_no': '201802061516184',
        'pub_key': """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCRnZYXXLskCaq4xazA7Mpx+3p
LPX/pywSD8m5ea2mxpfuaLbq5yUVL0sHwC2TXYO+ig5hhJo8D14o7sR16+ZUhui+
s/GkAB7bfj2VG2SQ/f3w0bLrgcgLU0efIhSBN52FjDywTuh4C0ibxaU6h9/NbTGz
ZXKyYzXPZtIA2uegTwIDAQAB
-----END PUBLIC KEY-----""",
        'pri_key': """-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQDCRnZYXXLskCaq4xazA7Mpx+3pLPX/pywSD8m5ea2mxpfuaLbq
5yUVL0sHwC2TXYO+ig5hhJo8D14o7sR16+ZUhui+s/GkAB7bfj2VG2SQ/f3w0bLr
gcgLU0efIhSBN52FjDywTuh4C0ibxaU6h9/NbTGzZXKyYzXPZtIA2uegTwIDAQAB
AoGBAJ2C4YqtYXMZQLCGY64KTuWOGn9WG7EGSf3u3P/K/pbcJux96+gyNeeiK3QC
RTFYvWrrpdM83ovZbd9EDvcIpvnxZ1zthIJKneh4AD+tZnLH49tJBgzwKqBP5Bah
xzNrvqtCVcvS8CVDPyxlFt56860gdhOl8O5hr1qQxqYhHNrJAkEA6DxYX8aFWdxw
NqqfKQ2vsZhcRtToqrFsJsJ4VYJKLRIvzH2WJ2sZ+5CNZclyw9ZdQUTdRnLynFYq
Ydi+nGlqqwJBANYns/wKtKjUzSkrZ+474S0lDFhoVqbQn/E5XjcmKt3X3NuaecCs
7wpObNBhMz1p9IJrk3SbFP99f2QQWL/voO0CQQDlu+R0gk8iUNXUzj56fyaBmcYW
78FmMfNZ+GDPvf6gzW/pa4bhYaqnWBz4Ryq3nlRMH9KBQW7MxtRQTPhqhEHXAkEA
sbKIGh8YAO9yvTKTLo7pLXiMYd9R52E9FgAwOTqmXyX60Q3A8SuNvdONXusIhXEh
vgZdeGgmaElOJ02ZFspTkQJANQ/aqyVYQzKqlwK9Ad2R+wGMdY/Gsvh8SEgUQaq7
MpMNXZt8/me4pgbVEF5+Fkxe0KLRpjx0/YpOxWS8RjG15g==
-----END RSA PRIVATE KEY-----""",
        'star_pub': '''-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCabJDz/66tGW6J0SBHI3zTqz+v
B7lkBwEcSnnaNJ6mAZ64Garc4Ax9lcFV9aUI3/v/w7LRnhPRnMCHc9HeBFS66jPi
xlvk3cB/TYsVoxuQInTE/VmQDv+9cRlKYpemULGr6VoeOzAoEHz68g/YUZCjFBxb
hTyOKutBoCorsAmQeQIDAQAB
-----END PUBLIC KEY-----''',
    },
}


def _get_gateway(mch_id):
    return APP_CONF[mch_id]['gateway']


def _get_h5_gateway(mch_id):
    return APP_CONF[mch_id]['h5_gateway']


def _get_query_gateway(mch_id):
    return APP_CONF[mch_id]['query_gateway']


def _get_union_quick_gateway(mch_id):
    return APP_CONF[mch_id]['union_quick_gateway']


def _get_pub_key(mch_id):
    return APP_CONF[mch_id]['pub_key']


def _get_pri_key(mch_id):
    return APP_CONF[mch_id]['pri_key']


def _get_star_pub_key(mch_id):
    return APP_CONF[mch_id]['star_pub']


def _get_terminal_no(mch_id):
    return APP_CONF[mch_id]['terminal_no']


def rsa_long_encrypt(pub_key_str, msg, length=64):
    """
    单次加密串的长度最大为 (key_size/8)-11
    1024bit的证书用100， 2048bit的证书用 200
    """
    pubobj = RSA.importKey(pub_key_str)
    pubobj = Cipher_pkcs1_v1_5.new(pubobj)
    res = []
    for i in range(0, len(msg), length):
        res.append(pubobj.encrypt(msg[i:i + length]))
    return "".join(res)


def rsa_long_decrypt(priv_key_str, msg, length=128):
    """
    1024bit的证书用128，2048bit证书用256位
    """
    privobj = RSA.importKey(priv_key_str, passphrase='614360')
    privobj = Cipher_pkcs1_v1_5.new(privobj)
    res = []
    for i in range(0, len(msg), length):
        res.append(privobj.decrypt(msg[i:i + length], 'xyz'))
    return "".join(res)


def _gen_rsa_sign(message, key):
    rsa_key = RSA.importKey(key)
    h = SHA.new(message)
    signer = Signature_pkcs1_v1_5.new(rsa_key)
    signature = signer.sign(h)
    return base64.b64encode(signature)


def _verify_sign(data, signature, key):
    data = base64.b64decode(data)
    key = RSA.importKey(key)
    h = SHA.new(data)
    verifier = Signature_pkcs1_v1_5.new(key)
    if verifier.verify(h, base64.b64decode(signature)):
        return True
    return False


def _get_pay_type(service):
    """
    1006: 支付宝扫码、1011: 支付宝WAP
    """
    if service == 'alipay':
        return '1011'
    elif service == 'alipay_scan':
        return '1006'
    elif service == 'union_quick':
        return '1024'
    return '1011'


def _get_app_type(service):
    """
    支付宝：1002
    """
    if service == 'alipay':
        return '1002'
    elif service == 'union_quick':
        return '1001'
    elif service == 'alipay_scan':
        return '1001'
    return '1002'


def _build_form(params, gateway):
    html = u"<head><title>loading...</title></head><form id='submit' name='submit' action='" + gateway + "' method='post'>"
    for k, v in params.items():
        html += "<input type='hidden' name='%s' value='%s'/>" % (k, v)
    html += "</form>"
    html += "<script>doc" \
            "ument.forms['submit'].submit();</script>"
    return html


def create_charge(pay, pay_amount, info):
    service = info.get('service')
    app_id = info['app_id']
    pri_key = _get_pri_key(app_id)
    parameter_dict = OrderedDict((
        ('asynURL', '{}/pay/api/{}/superstarpay/{}/'.format(settings.NOTIFY_PREFIX, settings.NOTIFY_PATH, app_id)),
        ('businessOrdid', str(pay.id)),
        ('merId', app_id),
        ('orderName', 'charge'),
        ('payType', _get_pay_type(service)),
        ('terId', _get_terminal_no(app_id)),
        ('appSence', _get_app_type(service)),
        ('tradeMoney', str(int(pay_amount * 100))),
    ))
    encrypt_str = rsa_long_encrypt(_get_star_pub_key(app_id),
                                   json.dumps(parameter_dict, sort_keys=True, separators=(',', ':')))
    parameter_dict['encParam'] = base64.b64encode(encrypt_str)
    parameter_dict['sign'] = _gen_rsa_sign(encrypt_str, _get_pri_key(app_id))
    parameter_dict['version'] = '1.0.9'
    _LOGGER.info("superstarpay requests data: %s, order_id is: %s", json.dumps(parameter_dict),
                 parameter_dict['businessOrdid'])
    if service == 'alipay':
        html_text = _build_form(parameter_dict, _get_h5_gateway(app_id))
        cache_id = redis_cache.save_html(pay.id, html_text)
        _LOGGER.info('superstarpay url: %s', settings.PAY_CACHE_URL + cache_id)
        return {'charge_info': settings.PAY_CACHE_URL + cache_id}
    elif service == 'alipay_scan':
        headers = {'Content-Type': 'application/x-www-form-urlencoded'}
        response = requests.post(_get_gateway(app_id), data=parameter_dict, headers=headers, timeout=5)
        _LOGGER.info("superstarpay create response is: %s", response.text)
        data = rsa_long_decrypt(pri_key, base64.b64decode(json.loads(response.text)['encParam']))
        _LOGGER.info("superstarpay resp data: %s", json.loads(data))
        return {'charge_info': json.loads(data)['code_img_url']}
    elif service == 'union_quick':
        html_text = _build_form(parameter_dict, _get_union_quick_gateway(app_id))
        cache_id = redis_cache.save_html(pay.id, html_text)
        _LOGGER.info('superstarpay url: %s', settings.PAY_CACHE_URL + cache_id)
        return {'charge_info': settings.PAY_CACHE_URL + cache_id}


def verify_notify_sign(params, pub_key):
    sign = params['sign']
    encParam = params['encParam']
    # _LOGGER.info("superstarpay sign: %s, encParam: %s", sign, encParam)
    if not _verify_sign(encParam, sign, pub_key):
        raise ParamError('superstarpay sign not pass')


# SUCCESS
def check_notify_sign(request, app_id):
    star_key = _get_star_pub_key(app_id)
    pri_key = _get_pri_key(app_id)
    data = dict(request.POST.iteritems())
    _LOGGER.info("superstarpay notify data: %s", data)
    verify_notify_sign(data, star_key)
    pay_id = data['orderId']
    if not pay_id:
        _LOGGER.error("fatal error, out_trade_no not exists, data: %s" % data)
        raise ParamError('superstarpay event does not contain pay ID')

    pay = order_db.get_pay(int(pay_id))
    if not pay:
        raise ParamError('pay_id: %s invalid' % pay_id)
    if pay.status != PAY_STATUS.READY:
        raise ParamError('pay %s has been processed' % pay_id)

    # 用私钥解签，获取参数
    data = rsa_long_decrypt(pri_key, base64.b64decode(data['encParam']))
    data = ast.literal_eval(data)  # string to dict

    mch_id = pay.mch_id
    trade_status = data['order_state']
    trade_no = data['payOrderId']
    total_fee = float(data['money']) / 100.0
    extend = {
        'trade_status': trade_status,
        'trade_no': trade_no,
        'total_fee': total_fee
    }

    check_channel_order(pay_id, total_fee, app_id)

    if trade_status == '1003' and total_fee > 0.0:
        _LOGGER.info('superstarpay check order success, mch_id:%s pay_id:%s' % (mch_id, pay_id))
        order_db.add_pay_success(mch_id, pay_id, total_fee, trade_no, extend)
        # async notify
        async_job.notify_mch(pay_id)


def query_charge(pay_order, app_id):
    pay_id = pay_order.id
    parameter_dict = OrderedDict((
        ('businessOrdid', str(pay_id)),
    ))
    encrypt_str = rsa_long_encrypt(_get_star_pub_key(app_id), json.dumps(parameter_dict))
    parameter_dict['encParam'] = base64.b64encode(encrypt_str)
    parameter_dict['sign'] = _gen_rsa_sign(encrypt_str, _get_pri_key(app_id))
    parameter_dict['merId'] = app_id
    parameter_dict['version'] = '1.0.9'
    _LOGGER.info("superstarpay query req data: %s", json.dumps(parameter_dict))
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    response = requests.post(_get_query_gateway(app_id), data=parameter_dict, headers=headers, timeout=5)
    _LOGGER.info("superstarpay query rsp code: %s, data: %s", response.status_code, response.text)

    if response.status_code == 200:
        star_key = _get_star_pub_key(app_id)
        pri_key = _get_pri_key(app_id)
        data = json.loads(response.text)

        verify_notify_sign(data, star_key)

        data = rsa_long_decrypt(pri_key, base64.b64decode(data['encParam']))
        data = ast.literal_eval(data)  # string to dict

        trade_status = data['order_state']
        total_fee = float(data['money']) / 100.0
        trade_no = data['payOrderId']
        extend = {
            'trade_status': trade_status,
            'trade_no': trade_no,
            'total_fee': total_fee
        }

        if trade_status == '1003':
            check_channel_order(pay_id, total_fee, app_id)

            _LOGGER.info('superstarpay query order success, mch_id:%s pay_id:%s' % (pay_order.mch_id, pay_id))
            order_db.add_pay_success(pay_order.mch_id, pay_id, total_fee, trade_no, extend)
            async_job.notify_mch(pay_order.id)
    else:
        _LOGGER.warn('superstarpay data error, status_code: %s', response.status_code)
